class (Functor f) => Applicative f where   
    pure :: a -> f a   
    (<*>) :: f (a -> b) -> f a -> f b
instance Applicative Maybe where   
    pure = Just   
    Nothing <*> _ = Nothing   
    (Just f) <*> something = fmap f something
(<$>) :: (Functor f) => (a -> b) -> f a -> f b   
f <$> x = fmap f x
instance Applicative [] where   
    pure x = [x]   
    fs <*> xs = [f x | f <- fs, x <- xs]
myAction :: IO String   
myAction = do   
    a <- getLine   
    b <- getLine   
    return $ a ++ b
applyMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
applyMaybe Nothing f  = Nothing   
applyMaybe (Just x) f = f x
--instance Monad Maybe where
--    return x = Just x
--    Nothing >>= f = Nothing
--    Just x >>= f = f x
--    fail _ = Nothing 
type Birds = Int   
type Pole = (Birds,Birds)
landLeft :: Birds -> Pole -> Maybe Pole   
landLeft n (left,right)   
    | abs ((left + n) - right) < 4 = Just (left + n, right)   
    | otherwise                    = Nothing   
           
landRight :: Birds -> Pole -> Maybe Pole   
landRight n (left,right)   
    | abs (left - (right + n)) < 4 = Just (left, right + n)   
    | otherwise                    = Nothing
x -: f = f x
banana :: Maybe Pole -> Maybe Pole   
banana _ = Nothing
routine :: Maybe Pole   
routine = case landLeft 1 (0,0) of   
    Nothing -> Nothing   
    Just pole1 -> case landRight 4 pole1 of    
            Nothing -> Nothing   
            Just pole2 -> case landLeft 2 pole2 of   
                    Nothing -> Nothing   
                    Just pole3 -> landLeft 1 pole3
wopwop :: Maybe Char   
wopwop = do   
    (x:xs) <- Just "hellowrold"   
    return x
listOfTuples :: [(Int,Char)]   
listOfTuples = do   
    n <- [1,2]   
    ch <- ['a','b']   
    return (n,ch)

class (Monad m) => MonadPlus m where   
    mzero :: m a   
    mplus :: m a -> m a -> m a

instance MonadPlus [] where   
    mzero = []   
    mplus = (++)

guard :: (MonadPlus m) => Bool -> m ()   
guard True = return ()   
guard False = mzero
type KnightPos = (Int,Int)
moveKnight :: KnightPos -> [KnightPos]   
moveKnight (c,r) = do   
    (c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1)   
                ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2)   
                ]   
    guard (c' `elem` [1..8] && r' `elem` [1..8]) 
    return (c',r')
in3 :: KnightPos -> [KnightPos]   
in3 start = do    
    first <- moveKnight start   
    second <- moveKnight first   
    moveKnight second
canReachIn3 :: KnightPos -> KnightPos -> Bool   
canReachIn3 start end = end `elem` in3 start
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)   
f <=< g = (\x -> g x >>= f)
